﻿/*************************************************************************************
 * 工    具：  HK_AutoGenerateTemplate
 * 
 * 描    述：  1. 本工具旨在根据QFramework框架规则，自动生成Unity项目的脚本模板和文件夹结构。
 *            2. 生成后会在 Assets 目录下创建 _Scripts 文件夹，并包含以下子文件夹：
 *               · Commands
 *               · Events
 *               · Models
 *               · Systems
 *               · ViewControllers
 *            3. 同时自动生成以下脚本：
 *               · [项目名]_Architecture.cs (或自定义名)
 *               · Controller.cs
 *               · IInitModel.cs
 *               · IRuntimeModel.cs
 *               · Events_Global.cs
 *               · IAudioSystem.cs
 *            4. 如果 _Scripts (或 _Script) 文件夹已存在，则会取消生成。
 *            5. 可自定义 Architecture 框架名称，用于命名脚本文件；若未指定，则默认使用当前工程ProductName。
 *            6. 点击“项目模板生成”按钮后，会进行二次确认以防误操作。
 *
 * 版    本：  V1.4
 * 作    者：  京产肠饭
 * 
 * 创    建：  2023/11/17  V1.0
 * 
 * 更    新：  2024/09/17  V1.1
 *            1.代码优化：通过字符串插值、逐字字符串$@符号，整理模板代码，提高模板代码维护性和可读性
 *            2.功能优化：IO操作时，增加try catch异常处理，提高健壮性
 *            3.功能优化：新增用户提示EditorUtility.DisplayDialog，关键步骤弹出提示框，提高用户体验
 *            
 *            2024/09/18  V1.2
 *            1.代码优化：模板代码及工具代码新增注释，提高代码的可读性，便于团队中的开发者理解模板代码
 *            
 *            2024/09/19  V1.3
 *            1.功能新增：新增 InitModel 数据模型层模板代码
 *            
 *            2025/02/03  V1.4
 *            1.功能优化：增加 Architecture 框架名生成的合法性过滤，去除数字开头及非法字符，并将首字母大写
 *            2.功能优化：生成脚本模板前，增加用户二次确认，防止误操作
 *            3.功能新增：新增 Architecture 名称自定义
 *            4.功能优化：重绘本工具的 EditorWindow 窗口
 *            
 * 链    接：  https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using HKTools;
using System;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

/// <summary>  
/// 自动生成项目脚本模板的工具。
/// </summary>  
public class HK_AutoGenerateTemplate : EditorWindow
{
    // 自定义架构名
    static string customArchitectureName = "";

    // 各类脚本模板代码
    string architectureCode;
    string controllerCode;
    string initModelCode;
    string runtimeModelCode;
    string audioSystemCode;
    string globalEventsCode;

    [MenuItem("HKTools/Auto Generate Template (自动化生成项目模板)", priority = HK_MenuPriority.HK_AutoGenerateTemplate)]
    static void Init()
    {
        HK_AutoGenerateTemplate generateTemplate = GetWindow<HK_AutoGenerateTemplate>(false, "Auto Generate Template", true);

        generateTemplate.Show();

        customArchitectureName = "";
    }

    void OnGUI()
    {
        // 上下留白  
        EditorGUILayout.Space();

        // 创建一个自定义的GUIStyle
        GUIStyle customLabelStyle = new GUIStyle(EditorStyles.wordWrappedLabel);
        customLabelStyle.fontSize = 11; // 设置字体大小
        customLabelStyle.normal.textColor = Color.white; // 设置字体颜色

        // 使用 GUI.Label 显示文本
        GUILayout.BeginVertical();
        GUILayout.Label("项目模板自动化生成注意事项：", customLabelStyle);

        GUILayout.Label("1. 本工具旨在根据QFramework框架规则，自动生成Unity项目的脚本模板和文件夹结构。", customLabelStyle);
        GUILayout.Label("2. 生成后会在 Assets 目录下创建 _Scripts 文件夹，并包含以下子文件夹：", customLabelStyle);
        GUILayout.Label("   · Commands", customLabelStyle);
        GUILayout.Label("   · Events", customLabelStyle);
        GUILayout.Label("   · Models", customLabelStyle);
        GUILayout.Label("   · Systems", customLabelStyle);
        GUILayout.Label("   · ViewControllers", customLabelStyle);
        GUILayout.Label("3. 同时自动生成以下脚本：", customLabelStyle);
        GUILayout.Label("   · [项目名]_Architecture.cs (或自定义名)", customLabelStyle);
        GUILayout.Label("   · Controller.cs", customLabelStyle);
        GUILayout.Label("   · IInitModel.cs", customLabelStyle);
        GUILayout.Label("   · IRuntimeModel.cs", customLabelStyle);
        GUILayout.Label("   · Events_Global.cs", customLabelStyle);
        GUILayout.Label("   · IAudioSystem.cs", customLabelStyle);
        GUILayout.Label("4. 如果 _Scripts (或 _Script) 文件夹已存在，则会取消生成。", customLabelStyle);
        GUILayout.Label("5. 可自定义 Architecture 框架名称，用于命名脚本文件；若未指定，则默认使用当前工程ProductName。", customLabelStyle);
        GUILayout.Label("6. 点击“项目模板生成”按钮后，会进行二次确认以防误操作。", customLabelStyle);

        GUILayout.EndVertical();

        EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);

        // 可以用一个Box把“框架名称”这部分包裹起来，视觉上更独立  
        EditorGUILayout.BeginVertical("box");
        {
            EditorGUILayout.Space();

            // 自定义框架名称的输入框  
            customArchitectureName = EditorGUILayout.TextField("自定义框架名称：", customArchitectureName, GUILayout.MinWidth(150), GUILayout.MaxWidth(500));

            EditorGUILayout.Space();

            // 生成模板的按钮，宽度200  
            if (GUILayout.Button("项目模板生成", GUILayout.MinWidth(150), GUILayout.MaxWidth(500)))
            {
                GenerateScriptsFolder();
                AssetDatabase.Refresh();
            }

            EditorGUILayout.Space();
        }
        EditorGUILayout.EndVertical();
    }

    /// <summary>
    /// 生成文件夹和脚本的方法，创建所需的文件夹结构并生成脚本文件。  
    /// </summary>
    void GenerateScriptsFolder()
    {
        // 检查是否已存在 _Scripts 或 _Script 文件夹
        bool isHaveScripts = (AssetDatabase.IsValidFolder("Assets/_Scripts") || AssetDatabase.IsValidFolder("Assets/_Script"));

        if (isHaveScripts)
        {
            EditorUtility.DisplayDialog("警告", "_Scripts文件夹已存在，取消生成操作。", "确定");
            HKDebug.LogWarning("_Scripts文件夹已存在");
            return;
        }

        if (!EditorUtility.DisplayDialog("确认", "即将生成遵循 QFramework 框架规则的项目代码模板，是否继续？", "确定", "取消"))
        {
            return;
        }

        string architecturName = customArchitectureName;

        if (string.IsNullOrEmpty(architecturName))
        {
            architecturName = Application.productName + "_Architecture";
        }

        // 获取项目名称，并移除所有空白字符（空格、制表符、换行等）
        architecturName = Regex.Replace(architecturName, @"\s", "");

        // 移除非法字符
        architecturName = Regex.Replace(architecturName, "[^a-zA-Z0-9_]", "_");

        // 去除开头所有数字  
        architecturName = Regex.Replace(architecturName, @"^\d+", "");

        //去除开头所有的下划线  
        architecturName = Regex.Replace(architecturName, "^_+", "");

        // 将首字母（若是小写）转换为大写  
        architecturName = Regex.Replace(architecturName, @"^[a-z]", m => m.Value.ToUpper());

        architectureCode =
$@"using QFramework;

/// <summary>
/// 项目架构类，继承自 QFramework 的 Architecture。
/// 负责注册项目中的模型层、工具层和系统层，是整个项目的核心架构。
/// </summary>
public class {architecturName} : Architecture<{architecturName}>
{{
    /// <summary>
    /// 初始化方法，用于注册模型层、工具层和系统层。
    /// </summary>
    protected override void Init()
    {{
        // 注册模型层
        this.RegisterModel<IInitModel>(new InitModel());
        this.RegisterModel<IRuntimeModel>(new RuntimeModel());

        // 注册系统层
        this.RegisterSystem<IAudioSystem>(new AudioSystem());
    }}
}}";

        controllerCode =
$@"using UnityEngine;
using QFramework;

/// <summary>
/// 控制器通用基类，所有视图层组件的基类，提供对本项目默认架构的引用。 
/// </summary>
public class Controller : MonoBehaviour, IController
{{
    public IArchitecture GetArchitecture()
    {{
        return {architecturName}.Interface;
    }}
}}";

        initModelCode =
$@"using QFramework;

/// <summary>
/// 定义初始化数据的模型层。
/// 存储和管理初始化数据，例如配置文件等。
/// </summary>
public interface IInitModel : IModel
{{

}}

public class InitModel : AbstractModel, IInitModel
{{
    protected override void OnInit()
    {{

    }}
}}";


        runtimeModelCode =
$@"using QFramework;

/// <summary>
/// 定义运行时数据的模型层。
/// 存储和管理运行时数据，例如各类状态、进度等。
/// </summary>
public interface IRuntimeModel : IModel
{{

}}

public class RuntimeModel : AbstractModel, IRuntimeModel
{{
    protected override void OnInit()
    {{

    }}
}}";

        audioSystemCode =
$@"using QFramework;
using UnityEngine.UI;

/// <summary>
/// 音频管理系统层，定义音频系统的功能。
/// 负责管理音频播放、音量控制等。
/// </summary>
public interface IAudioSystem : ISystem
{{

}}

public class AudioSystem : AbstractSystem, IAudioSystem
{{
    /// <summary>
    /// 初始化音频系统，注册按钮和切换控件的默认音频事件等。
    /// </summary>
    protected override void OnInit()
    {{
        // 注册 HK_Button 按钮点击事件的音频回调
        HK_Button.defaultAudio_Event += OnClickHKButton;

        // 注册 HK_Toggle 点击事件的音频回调
        HK_Toggle.defaultAudio_Event += OnClickHKToggle;
    }}

    void OnClickHKButton()
    {{

    }}

    void OnClickHKToggle()
    {{

    }}
}}";

        globalEventsCode =
$@"/// **********  
/// 定义全局事件的脚本，用于声明全局范围内的事件和消息。  
/// **********";

        try
        {
            // 创建文件夹结构
            AssetDatabase.CreateFolder("Assets", "_Scripts");
            AssetDatabase.CreateFolder("Assets/_Scripts", "Commands");
            AssetDatabase.CreateFolder("Assets/_Scripts", "Events");
            AssetDatabase.CreateFolder("Assets/_Scripts", "Models");
            AssetDatabase.CreateFolder("Assets/_Scripts", "Systems");
            AssetDatabase.CreateFolder("Assets/_Scripts", "ViewControllers");
        }
        catch (Exception e)
        {
            HKDebug.LogError($"创建文件夹失败：{e.Message}");
        }

        try
        {
            // 写入脚本文件
            File.WriteAllText("Assets/_Scripts/" + architecturName + ".cs", architectureCode);
            File.WriteAllText("Assets/_Scripts/Controller.cs", controllerCode);
            File.WriteAllText("Assets/_Scripts/Models/IInitModel.cs", initModelCode);
            File.WriteAllText("Assets/_Scripts/Models/IRuntimeModel.cs", runtimeModelCode);
            File.WriteAllText("Assets/_Scripts/Events/Events_Global.cs", globalEventsCode);
            File.WriteAllText("Assets/_Scripts/Systems/IAudioSystem.cs", audioSystemCode);
        }
        catch (Exception e)
        {
            HKDebug.LogError($"模板代码写入失败：{e.Message}");
        }
    }
}
